Interactive Choropleth using Plotly
Map sourced from Datameet maps
Data sourced from myneta
import json
import numpy as np
import pandas as pd
from matplotlib.colors import Normalize
from matplotlib import cm
from itertools import product
import copy
from plotly.offline import init_notebook_mode, iplot
init_notebook_mode(connected=True)
import plotly.plotly as ply
from collections import defaultdict
MAPBOX_APIKEY = "Your Mapbox key"
with open('merged_2019_pc_map_1pc_trim.json') as f:
geojson = json.load(f)
# Print a sample of properties in geojson file
[geojson['features'][1]['properties']]
# Get number of PCs
n_pc = len(geojson['features'])
print("there are {} PCs ".format(n_pc))
def get_centers():
lon, lat =[], []
for k in range(n_pc):
geometry = geojson['features'][k]['geometry']
if geometry['type'] == 'Polygon':
coords=np.array(geometry['coordinates'][0])
elif geometry['type'] == 'MultiPolygon':
coords=np.array(geometry['coordinates'][0][0])
lon.append(sum(coords[:,0]) / len(coords[:,0]))
lat.append(sum(coords[:,1]) / len(coords[:,1]))
return lon, lat
def make_sources():
sources = []
geojson_copy = copy.deepcopy(geojson['features'])
for feature in geojson_copy:
sources.append(dict(type = 'FeatureCollection',
features = [feature])
)
return sources
# create list of tuples having touple format (PC_NAME_x, Criminal_C)
pc_list = [geojson['features'][k]['properties']['PC_NAME_x'] for k in range(n_pc)]
asset_list = [geojson['features'][k]['properties']['Assets_num'] for k in range(n_pc)]
mp_list = [geojson['features'][k]['properties']['Candidate'] for k in range(n_pc)]
pc_asset_dict = dict(PC_NAME = pc_list, Assets_num = asset_list, Candidate = mp_list)
# pc_crime_dict
# Create dataframe from list of touples
pc_asset_df = pd.DataFrame(pc_asset_dict)
pc_asset_df.head()
# find the NaNs in the df
# pc_crime_df[pc_crime_df['CriminalC'].isna()]
def scalarmappable(cmap, cmin, cmax):
colormap = cm.get_cmap(cmap)
norm = Normalize(vmin=cmin, vmax=cmax)
print(norm)
return cm.ScalarMappable(norm=norm, cmap=colormap)
def get_scatter_colors(sm, df):
grey = 'rgba(0, 0,128,0.6)'
return ['rgba' + str(sm.to_rgba(m, bytes = True, alpha = 1)) if not np.isnan(m) else grey for m in df['Assets_num']]
def get_colorscale(sm, df, cmin, cmax):
xrange = np.linspace(0, 1, len(df))
values = np.linspace(cmin, cmax, len(df))
return [[i, 'rgba' + str(sm.to_rgba(v, bytes = True))] for i,v in zip(xrange, values) ]
def get_hover_text(df) :
# convert array of int to array of string
text_value = [int(x) if not np.isnan(x) else 0 for x in df.Assets_num]
with_data = '<b>Constituency: {}</b> <br><b>Candidate: {}</b><br><b>Assets(Rs): {:,}</b>'
no_data = '<b>{}</b> <br> no data'
return [with_data.format(p,v, q) if v else no_data.format(p) for p,v,q in zip(df.PC_NAME, df.Candidate, text_value)]
colormap = 'YlGn'
cmin = min(pc_asset_df.Assets_num)
cmax = max(pc_asset_df.Assets_num)
sources = make_sources()
lons, lats = get_centers()
sm = scalarmappable(colormap, cmin, cmax)
scatter_colors = get_scatter_colors(sm, pc_asset_df)
colorscale = get_colorscale(sm, pc_asset_df, cmin, cmax)
hover_text = get_hover_text(pc_asset_df)
tickformat = ",d"
data = dict(type='scattermapbox',
lat=lats,
lon=lons,
mode='markers',
text=hover_text,
marker=dict(size=1,
color=scatter_colors,
showscale = True,
cmin = cmin,
cmax = cmax,
colorscale = colorscale,
colorbar=dict(tickformat=tickformat,
# tickprefix= "Rs. ",
title="Assets (In Rs.)",
titlefont = dict(size=14,
family='Arial, sans-serif'
),
titleside='right'
)
),
showlegend=False,
hoverinfo='text'
)
layers=([dict(sourcetype = 'geojson',
source =sources[k],
below="",
type = 'line',
line = dict(width = 0.1),
color = 'black',
) for k in range(n_pc)] +
[dict(sourcetype = 'geojson',
source =sources[k],
below="water",
type = 'fill',
color = scatter_colors[k],
opacity=0.8
) for k in range(n_pc)]
)
layout = dict(title="Assets of MPs elected in LokSabha Election (2019) <br> " +
"""using data from http://www.myneta.info""",
autosize=False,
width=880, #700,
height=930, #800
hovermode='closest',
hoverdistance = 30,
mapbox=dict(accesstoken=MAPBOX_APIKEY,
layers=layers,
bearing=0,
center=dict(
lat=23,
lon=82.5),
pitch=0,
zoom=4,
style = 'light'
)
)
fig = dict(data=[data], layout=layout)
iplot(fig)